﻿using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Collections.Specialized;
using FlexiCache;
using UnitTests.IISSimulator;

namespace CLOComponentlibCSFixture.FlexiCache
{
    [TestClass]
    public class OutputCacheProviderTests
    {
        ExternalOutputCacheProvider _provider;

        [TestInitialize]
        public void BeforeTest()
        {
            _provider = new ExternalOutputCacheProvider();
        }

        [TestMethod]
        public void Test001_DoConnectionTest()
        {
            _provider.ConnectionTest();
        }

        [TestMethod]
        public void Test002_ShouldSaveNewObjectToCache()
        {
            string key = @"a2/clo/clo/assignments/courses/courseentitypresenter.restHQNcourseidV259899NusernameVLennyFCDE";

            _provider.Add(key, "Hello MongoDB", DateTime.UtcNow.AddSeconds(100));
            var obj = _provider.Get(key);

            Assert.AreEqual("Hello MongoDB", obj);

            _provider.Remove(key);
        }

        [TestMethod]
        public void Test003_ShouldGetExistingObjectFromCache()
        {
            string key = "98762";

            _provider.Add(key, "Saved Item", DateTime.UtcNow.AddSeconds(100));
            var obj = _provider.Get(key);

            Assert.AreEqual("Saved Item", obj);

            _provider.Remove(key);
        }

        [TestMethod]
        public void Test004_ShouldNotGetNonExistentObjectFromCache()
        {
            string key = "90877000";

            var obj = _provider.Get(key);

            Assert.IsNull(obj);
        }

        [TestMethod]
        public void Test005_ShouldNotGetExpiredObjectFromCache()
        {
            string key = "98734234";

            _provider.Add(key, "This has expired already!", DateTime.UtcNow.AddSeconds(-10));
            var obj = _provider.Get(key);

            Assert.IsNull(obj);
        }

        [TestMethod]
        public void Test006_AddShouldNotUpdateExistingItemInCache()
        {
            string key = "9873";

            _provider.RemoveAll();
            _provider.Add(key, "Existing Item", DateTime.UtcNow.AddSeconds(100));
            _provider.Add(key, "Updated Item", DateTime.UtcNow.AddSeconds(100));
            var obj = _provider.Get(key);

            Assert.AreEqual("Existing Item", obj);
        }

        [TestMethod]
        public void Test007_AddShouldUpdateExpiredItemInCache()
        {
            string key = "564536787";

            _provider.RemoveAll();
            _provider.Add(key, "This has expired already!", DateTime.UtcNow.AddSeconds(-10));
            _provider.Add(key, "This hasn't", DateTime.UtcNow.AddSeconds(10));
            var obj = _provider.Get(key);

            Assert.AreEqual("This hasn't", obj);
        }

        [TestMethod]
        public void Test008_SetShouldUpdateExistingObjectFromCache()
        {
            string key = "45645464";

            _provider.RemoveAll();
            _provider.Add(key, "New Document", DateTime.UtcNow.AddSeconds(100));
            _provider.Set(key, "Updated Document", DateTime.UtcNow.AddSeconds(100));
            var obj = _provider.Get(key);

            Assert.AreEqual("Updated Document", obj);

            _provider.Remove(key);
        }

        [TestMethod]
        public void Test009_ShouldRemoveValidObjectFromCache()
        {
            string key = "08977";

            _provider.Add(key, "Document to be deleted", DateTime.UtcNow.AddSeconds(100));
            _provider.Remove(key);

            var obj = _provider.Get(key);

            Assert.IsNull(obj);
        }

        [TestMethod]
        public void Test010_CountShouldBeValid()
        {
            _provider.RemoveAll();
            _provider.Add("089776466", "Document # 1", DateTime.UtcNow.AddSeconds(100));
            _provider.Add("089776467", "Document # 2", DateTime.UtcNow.AddSeconds(100));

            long obj = _provider.GetCount();

            Assert.AreEqual(2, obj, "The number of items should be 2.");
        }

        [TestMethod]
        public void Test011_ShouldBeAbleToRemoveAllItems()
        {
            _provider.Add("089776468", "Document # 3", DateTime.UtcNow.AddSeconds(100));
            _provider.Add("089776469", "Document # 4", DateTime.UtcNow.AddSeconds(100));

            _provider.RemoveAll();
            long obj = _provider.GetCount();

            Assert.AreEqual(0, obj, "The number of items should be 0.");
        }

        [TestMethod]
        public void Test012_ShouldRemoveExpiredItems()
        {
            _provider.RemoveAll();
            _provider.Add("089776446", "Document # 5", DateTime.UtcNow.AddSeconds(-100));
            _provider.Add("089776447", "Document # 6", DateTime.UtcNow.AddSeconds(-100));
            _provider.Add("089776448", "Document # 7", DateTime.UtcNow.AddSeconds(100));

            _provider.RemoveExpired();
            long obj = _provider.GetCount();

            Assert.AreEqual(1, obj, "The number of items should be 1.");
        }

        [TestMethod]
        [Ignore()]
        public void Test014_Speedtest1()
        {
            System.Diagnostics.Stopwatch timer = new System.Diagnostics.Stopwatch();
            timer.Start();
            System.Diagnostics.Stopwatch timer2 = new System.Diagnostics.Stopwatch();
            string key = "";
            byte[] data = null;
            Random rnd = new Random(DateTime.Today.Millisecond);
            int iterationCount = 100;
            System.Security.Cryptography.RandomNumberGenerator gen = System.Security.Cryptography.RandomNumberGenerator.Create();
            System.Text.StringBuilder sbr = new StringBuilder("Length,Duration\n");
            for (int ii = 0; ii < iterationCount; ii++)
            {
                //System.Threading.Thread.Sleep(1000);
                timer2.Restart();
                key = Guid.NewGuid().ToString();
                data = new byte[rnd.Next(500, 100000)];//~0.5- ~100Kb
                gen.GetBytes(data);
                _provider.Add(key, data, DateTime.UtcNow.AddSeconds(1000));
                _provider.Get(key);
                sbr.AppendFormat("{0},{1}\n", data.Length.ToString(), timer2.Elapsed.TotalMilliseconds.ToString("F2"));
            }
            timer.Stop();
            _provider.RemoveAll();
            System.Diagnostics.Trace.WriteLine(string.Format("Speedtest for {0} completed in {1} ms. Avg: {2} ms.", iterationCount.ToString(), timer.ElapsedMilliseconds.ToString(), (Convert.ToDecimal(timer.ElapsedMilliseconds) / Convert.ToDecimal(iterationCount)).ToString("F2")));
            System.IO.File.WriteAllText(@"C:\outputTest014_Speedtest1-2.csv", sbr.ToString());
        }

        [TestMethod]
        [Ignore()]
        public void Test015_Compact()
        {
            _provider.Compact();
        }

        [TestMethod]
        public void Test016_SetGetWithCompression()
        {
             _provider.Dispose();
            _provider = new ExternalOutputCacheProvider(true); //UseCompression
            System.Diagnostics.Stopwatch timer = new System.Diagnostics.Stopwatch();
            timer.Start();
            string key = Guid.NewGuid().ToString();
            Random rnd = new Random(DateTime.Today.Millisecond);
            byte[] data = new byte[rnd.Next(200000, 1000000)];
            System.Security.Cryptography.RandomNumberGenerator gen = System.Security.Cryptography.RandomNumberGenerator.Create();
            gen.GetBytes(data);
            _provider.Add(key, data, DateTime.UtcNow.AddSeconds(1000));
            _provider.Get(key);
            timer.Stop();
            _provider.RemoveAll();
            System.Diagnostics.Trace.WriteLine(string.Format("SetGetWithCompression for {0} bytes completed in {1} ms.)", data.Length.ToString(), timer.ElapsedMilliseconds.ToString()));
        }

        [TestMethod()]
        public void Test017_RemoveOutputCachedItemByMetaTagsWholeFlowTest()
        {
            string requestUrl = @"http://www.test.com/clo/clo/assignments/courses/courseentitypresenter.rest?courseid=259899&username=Lenny";
            string cacheKey = @"a2/clo/clo/assignments/courses/courseentitypresenter.restHQNcourseidV259899NusernameVLennyFCDE";

            _provider.RemoveAll();
            _provider.Add("089776446", "Document # 5", DateTime.UtcNow.AddSeconds(100));
            _provider.Add("089776447", "Document # 6", DateTime.UtcNow.AddSeconds(100));
            HttpSimulator sim = null;
            try
            {
                sim = new HttpSimulator("/", true);
                NameValueCollection vars = new NameValueCollection();
                sim.SimulateRequest(new Uri(requestUrl), vars);

                _provider.Add(cacheKey, "Document # 7", DateTime.UtcNow.AddSeconds(100));

                _provider.Remove("", new string[] { "courseid=259899" });
                long obj = _provider.GetCount();

                Assert.AreEqual(2, obj, "The number of items should be 2.");
            }
            finally
            {
                if (sim != null)
                    sim.Dispose();
            }
        }

        [TestMethod]
        [Ignore()]
        public void Test018_Speedtest3CompareWithAndWithoutCacheProviderConstruction()
        {
            System.Diagnostics.Stopwatch timer = new System.Diagnostics.Stopwatch();
            timer.Start();
            string key = "";
            int iterationCount = 1000;
            ExternalOutputCacheProvider provider = new ExternalOutputCacheProvider();
            for (int ii = 0; ii < iterationCount; ii++)
            {
                key = "089776446" + ii.ToString();
                provider.Add(key, "Document # " + ii.ToString(), DateTime.UtcNow.AddSeconds(1000));
                provider.Get(key);
            }
            timer.Stop();
            provider.RemoveAll();
            System.Diagnostics.Trace.WriteLine(string.Format("Speedtest for {0} completed in {1} ms. Avg: {2} ms.", iterationCount.ToString(), timer.ElapsedMilliseconds.ToString(), (Convert.ToDecimal(timer.ElapsedMilliseconds) / Convert.ToDecimal(iterationCount)).ToString("F2")));
            
            timer.Start();
            for (int ii = 0; ii < iterationCount; ii++)
            {
                key = "089776446" + ii.ToString();
                provider = new ExternalOutputCacheProvider();
                provider.Add(key, "Document # " + ii.ToString(), DateTime.UtcNow.AddSeconds(1000));
                provider.Get(key);
            }
            timer.Stop();
            provider.RemoveAll();
            System.Diagnostics.Trace.WriteLine(string.Format("Speedtest for {0} completed in {1} ms. Avg: {2} ms.", iterationCount.ToString(), timer.ElapsedMilliseconds.ToString(), (Convert.ToDecimal(timer.ElapsedMilliseconds) / Convert.ToDecimal(iterationCount)).ToString("F2")));
        }

        [TestCleanup]
        public void Cleanup()
        {
            _provider.Dispose();
        }
    }
}
